package com.cjl.net.nio;

import java.io.IOError;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Iterator;
import java.util.Set;

public class NIOServer {

    public static void main(String[] args) {
        new Thread(new NIOServerHandler(10001)).start();
    }

    static class NIOServerHandler implements Runnable{
        private volatile boolean started;
        private ServerSocketChannel serverSocketChannel;
        private Selector selector;
        private int port;


        public NIOServerHandler(int port) {
            this.port = port;
            try {
                serverSocketChannel = ServerSocketChannel.open();
                selector = Selector.open();
                serverSocketChannel.socket().bind(new InetSocketAddress(port));
                started = true;
                serverSocketChannel.configureBlocking(false);
                serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
                System.out.println("NIOServerHandler.NIOServerHandler Server Start...");
            }catch (IOException e){
                e.printStackTrace();
            }
        }

        @Override
        public void run() {
            while (started){
                SelectionKey selectionKey = null;
                try {
                    //等待1s或有事件 均会唤醒
                    selector.select(1000);
                    Set<SelectionKey> selectionKeys = selector.selectedKeys();
                    Iterator<SelectionKey> iterator = selectionKeys.iterator();

                    while (iterator != null && iterator.hasNext()){
                        selectionKey = iterator.next();
                        iterator.remove();
                        if (selectionKey.isAcceptable()){
                            ServerSocketChannel serverSocketChannelSlaver = (ServerSocketChannel) selectionKey.channel();
                            SocketChannel accept = serverSocketChannelSlaver.accept();
                            accept.configureBlocking(false);
                            accept.register(selector,SelectionKey.OP_READ);

                        }
                        if (selectionKey.isReadable()){
                            ByteBuffer buffer = ByteBuffer.allocate(1024);
                            SocketChannel acceptSlaver = (SocketChannel) selectionKey.channel();

                            int readBytes = acceptSlaver.read(buffer);
                            if (readBytes > 0){
                                buffer.flip();
                                byte[] bytes = new byte[readBytes];
                                buffer.get(bytes);
                                System.out.println("NIOServerHander.get MSG from Client: "+new String(bytes,"UFT-8"));

                                sendMsg(acceptSlaver,"hi client,xxx from server");
                            }else if (readBytes < 0){
                                selectionKey.cancel();
                                serverSocketChannel.close();
                            }

                        }
                    }
                    if (selector != null){
                        selector.close();
                    }
                }catch (Exception e){
                    e.printStackTrace();
                    if (selectionKey != null){
                        selectionKey.cancel();
                        if (selectionKey.channel() != null){
                            try {
                                selectionKey.channel().close();
                            } catch (IOException ioException) {
                                ioException.printStackTrace();
                            }
                        }
                    }
                }
            }
        }

        private void sendMsg(SocketChannel acceptSlaver, String s) throws IOException {
            byte[] bytes = s.getBytes();
            ByteBuffer writeBuffer = ByteBuffer.allocate(bytes.length);
            writeBuffer.put(bytes);
            writeBuffer.flip();
            acceptSlaver.write(writeBuffer);
        }

        public void stop(){
            started = false;
        }
    }
}
